package com.xli.organ.role.framerole.service.impl;

import com.alicp.jetcache.Cache;
import com.alicp.jetcache.CacheManager;
import com.alicp.jetcache.anno.CacheConsts;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.template.QuickConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xli.dto.component.util.TreeUtil;
import com.xli.organ.role.framerole.entity.FrameRole;
import com.xli.organ.role.framerole.entity.RoleCache;
import com.xli.organ.role.framerole.mapper.FrameRoleMapper;
import com.xli.organ.role.framerole.mapper.IRoleCacheMapper;
import com.xli.organ.role.framerole.service.IFrameRoleService;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.time.Duration;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Validated
@Service
public class FrameRoleServiceImpl extends ServiceImpl<FrameRoleMapper, FrameRole> implements IFrameRoleService {

    private final Lock lock = new ReentrantLock();

    @Autowired
    CacheManager cacheManager;

    Cache<Long, List<RoleCache>> roleCache;

    @PostConstruct
    public void init() {
        lock.lock();
        try {
            QuickConfig qc = QuickConfig.newBuilder("frame_role:list:")
                    .expire(Duration.ofSeconds(CacheConsts.DEFAULT_EXPIRE))
                    .cacheType(CacheType.LOCAL)
                    .syncLocal(true)
                    .build();
            roleCache = cacheManager.getOrCreateCache(qc);

            List<FrameRole> frameRoleList = this.findList(new QueryWrapper<>());
            List<RoleCache> roleCacheList = IRoleCacheMapper.INSTANCE.toCacheList(frameRoleList);

            Map<Long, List<RoleCache>> groupList = roleCacheList.stream()
                    .collect(Collectors.groupingBy(role -> Optional.ofNullable(role.getCategory_id()).orElse(TreeUtil.defaultPid)));
            groupList.forEach((categoryId, roleList) -> {
                roleList.sort(Comparator.comparing(RoleCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                roleCache.put(categoryId, roleList);
            });
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean insert(FrameRole frameRole) {
        lock.lock();
        try {
            boolean result = this.save(frameRole);
            if (result) {
                List<RoleCache> roleCacheList = roleCache.get(generateKey(frameRole));
                if (roleCacheList == null) {
                    roleCacheList = new ArrayList<>();
                }
                roleCacheList.add(IRoleCacheMapper.INSTANCE.toCacheEntity(frameRole));
                roleCacheList.sort(Comparator.comparing(RoleCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                roleCache.put(generateKey(frameRole), roleCacheList);
            }
            return result;
        } finally {
            lock.unlock();
        }

    }

    @Override
    public boolean delete(Long id) {
        lock.lock();
        try {
            FrameRole frameRole = this.find(id);
            if (frameRole != null) {
                boolean result = this.removeById(id);
                if (result) {
                    List<RoleCache> roleCacheList = roleCache.get(generateKey(frameRole));
                    if (roleCacheList == null) {
                        roleCacheList = new ArrayList<>();
                    }
                    roleCacheList.removeIf(cache -> cache.getId().equals(frameRole.getId()));
                    roleCache.put(generateKey(frameRole), roleCacheList);
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public boolean update(FrameRole frameRole) {
        lock.lock();
        try {
            FrameRole role = this.find(frameRole.getId());
            if (role != null) {
                boolean result = this.updateById(frameRole);
                if (result) {
                    List<RoleCache> roleCacheList = roleCache.get(generateKey(role));
                    if (roleCacheList == null) {
                        roleCacheList = new ArrayList<>();
                    }
                    roleCacheList.removeIf(cache -> cache.getId().equals(role.getId()));
                    if (role.getCategory_id().equals(frameRole.getCategory_id())) {
                        roleCacheList.add(IRoleCacheMapper.INSTANCE.toCacheEntity(frameRole));
                        roleCacheList.sort(Comparator.comparing(RoleCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                        roleCache.put(generateKey(role), roleCacheList);
                    } else {
                        roleCache.put(generateKey(role), roleCacheList);
                        roleCacheList = roleCache.get(generateKey(frameRole));
                        if (roleCacheList == null) {
                            roleCacheList = new ArrayList<>();
                        }
                        roleCacheList.add(IRoleCacheMapper.INSTANCE.toCacheEntity(frameRole));
                        roleCacheList.sort(Comparator.comparing(RoleCache::getOrder_num, Comparator.nullsLast(Comparator.reverseOrder())));
                        roleCache.put(generateKey(frameRole), roleCacheList);
                    }
                }
                return result;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public FrameRole find(Long id) {
        return this.getById(id);
    }

    @Override
    public List<FrameRole> findList(QueryWrapper<FrameRole> qw) {
        return this.list(qw);
    }

    @Override
    public long findCount(QueryWrapper<FrameRole> qw) {
        return this.count(qw);
    }

    @Override
    public Page<FrameRole> findList(QueryWrapper<FrameRole> qw, long current, long size) {
        return this.page(new Page<>(current, size), qw);
    }

    @Override
    public List<FrameRole> findAllRoleList() {
        return this.findList(new QueryWrapper<>());
    }

    @Override
    public FrameRole findByName(String name) {
        QueryWrapper<FrameRole> qw = new QueryWrapper<>();
        qw.lambda().eq(FrameRole::getRole_name, name);
        return this.getOne(qw);
    }

    private Long generateKey(FrameRole frameRole) {
        if (frameRole != null && frameRole.getCategory_id() != null) {
            return frameRole.getCategory_id();
        }
        return TreeUtil.defaultPid;
    }
}
